//
// @Auther: by wujehy 
// @Email:wujehy@qq.com
// @Data:20-2-14
// @Time:下午4:26
//

#include <openssl/ossl_typ.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <uthash.h>
#include <signal_protocol_internal.h>
#include "Common.h"

using namespace GeeJoan::E2EE;

int64_t GeeJoan::E2EE::Common::jenkins_hash(const char *key, size_t len)
{
    uint64_t hash, i;
    for (hash = i = 0; i < len; ++i)
    {
        hash += key[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);
    return hash;
}

int Common::common_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len,
                                    void *user_data)
{
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
    HMAC_CTX *ctx = HMAC_CTX_new();
    if (!ctx)
    {
        return SG_ERR_NOMEM;
    }
#else
    HMAC_CTX *ctx = malloc(sizeof(HMAC_CTX));
    if(!ctx) {
        return SG_ERR_NOMEM;
    }
    HMAC_CTX_init(ctx);
#endif

    *hmac_context = ctx;

    if (HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), 0) != 1)
    {
        return SG_ERR_UNKNOWN;
    }

    return 0;
}

int Common::common_random_generator(uint8_t *data, size_t len, void *user_data)
{
    if (RAND_bytes(data, len))
    {
        return 0;
    } else
    {
        return SG_ERR_UNKNOWN;
    }
}


int
Common::common_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len,
                                  void *user_data)
{
    HMAC_CTX *ctx = (HMAC_CTX *) hmac_context;
    int result = HMAC_Update(ctx, data, data_len);
    return (result == 1) ? 0 : -1;
}

int Common::common_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data)
{
    int result = 0;

    bool isComplete = false; // 标记是否结束
    unsigned char md[EVP_MAX_MD_SIZE];
    unsigned int len = 0;
    HMAC_CTX *ctx = (HMAC_CTX *) hmac_context;

    if (HMAC_Final(ctx, md, &len) != 1)
    {
        return SG_ERR_UNKNOWN;
    }

    signal_buffer *output_buffer = signal_buffer_create(md, len);
    if (!output_buffer)
    {
        result = SG_ERR_NOMEM;
        isComplete = true;
    }
    if (!isComplete)
    {
        *output = output_buffer;
    }

    return result;
}

void Common::common_hmac_sha256_cleanup(void *hmac_context, void *user_data)
{
    if (hmac_context)
    {
        HMAC_CTX *ctx = (HMAC_CTX *) hmac_context;
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
        HMAC_CTX_free(ctx);
#else
        HMAC_CTX_cleanup(ctx);
        free(ctx);
#endif
    }
}


int Common::common_sha512_digest_init(void **digest_context, void *user_data)
{
    int result = 0;
    bool isComplete = false; // 标记是否结束
    EVP_MD_CTX *ctx;

    ctx = EVP_MD_CTX_create();
    if (!ctx)
    {
        result = SG_ERR_NOMEM;
        isComplete = true;
    }
    // 没有结束 则 继续操作
    if (!isComplete)
    {
        result = EVP_DigestInit_ex(ctx, EVP_sha512(), 0);
        if (result == 1)
        {
            result = SG_SUCCESS;
        } else
        {
            result = SG_ERR_UNKNOWN;
        }
    }

    if (result < 0)
    {
        if (ctx)
        {
            EVP_MD_CTX_destroy(ctx);
        }
    } else
    {
        *digest_context = ctx;
    }
    return result;
}

int Common::common_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len,
                                        void *user_data)
{
    EVP_MD_CTX *ctx = (EVP_MD_CTX *) digest_context;

    int result = EVP_DigestUpdate(ctx, data, data_len);

    return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN;
}

int Common::common_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data)
{
    int result = 0;
    bool isComplete = false;
    unsigned char md[EVP_MAX_MD_SIZE];
    unsigned int len = 0;
    EVP_MD_CTX *ctx = (EVP_MD_CTX *) digest_context;

    result = EVP_DigestFinal_ex(ctx, md, &len);
    if (result == 1)
    {
        result = SG_SUCCESS;
    } else
    {
        result = SG_ERR_UNKNOWN;
        isComplete = true;
    }

    if (!isComplete)
    {
        result = EVP_DigestInit_ex(ctx, EVP_sha512(), 0);
        if (result == 1)
        {
            result = SG_SUCCESS;
        } else
        {
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }
    }
    signal_buffer *output_buffer;
    if (!isComplete)
    {
        output_buffer = signal_buffer_create(md, len);
        if (!output_buffer)
        {
            result = SG_ERR_NOMEM;
            isComplete = true;
        }
    }

    if (!isComplete)
    {
        *output = output_buffer;
    }
    return result;
}

void Common::common_sha512_digest_cleanup(void *digest_context, void *user_data)
{
    EVP_MD_CTX *ctx = (EVP_MD_CTX *) digest_context;
    EVP_MD_CTX_destroy(ctx);
}

const EVP_CIPHER *aes_cipher(int cipher, size_t key_len)
{
    if (cipher == SG_CIPHER_AES_CBC_PKCS5)
    {
        if (key_len == 16)
        {
            return EVP_aes_128_cbc();
        } else if (key_len == 24)
        {
            return EVP_aes_192_cbc();
        } else if (key_len == 32)
        {
            return EVP_aes_256_cbc();
        }
    } else if (cipher == SG_CIPHER_AES_CTR_NOPADDING)
    {
        if (key_len == 16)
        {
            return EVP_aes_128_ctr();
        } else if (key_len == 24)
        {
            return EVP_aes_192_ctr();
        } else if (key_len == 32)
        {
            return EVP_aes_256_ctr();
        }
    }
    return 0;
}

int Common::common_encrypt(signal_buffer **output,
                           int cipher,
                           const uint8_t *key, size_t key_len,
                           const uint8_t *iv, size_t iv_len,
                           const uint8_t *plaintext, size_t plaintext_len,
                           void *user_data)
{
    int result = 0;
    bool isComplete = false;
    EVP_CIPHER_CTX *ctx = 0;
    uint8_t *out_buf = 0;

    const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len);
    if (!evp_cipher)
    {
        fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len);
        return SG_ERR_UNKNOWN;
    }

    if (iv_len != 16)
    {
        fprintf(stderr, "invalid AES IV size: %zu\n", iv_len);
        return SG_ERR_UNKNOWN;
    }

    if (plaintext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher))
    {
        fprintf(stderr, "invalid plaintext length: %zu\n", plaintext_len);
        return SG_ERR_UNKNOWN;
    }

#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
    if (!isComplete)
    {
        ctx = EVP_CIPHER_CTX_new();
        if (!ctx)
        {
            result = SG_ERR_NOMEM;
            isComplete = true;
        }
    }

#else
    if(!isComplete){
        ctx = malloc(sizeof(EVP_CIPHER_CTX));
        if(!ctx) {
            result = SG_ERR_NOMEM;
            isComplete=true;
        }
        EVP_CIPHER_CTX_init(ctx);
    }

#endif


    if (!isComplete)
    {
        result = EVP_EncryptInit_ex(ctx, evp_cipher, 0, key, iv);
        if (!result)
        {
            fprintf(stderr, "cannot initialize cipher\n");
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }
    }

    if (!isComplete)
    {
        if (cipher == SG_CIPHER_AES_CTR_NOPADDING)
        {
            result = EVP_CIPHER_CTX_set_padding(ctx, 0);
            if (!result)
            {
                fprintf(stderr, "cannot set padding\n");
                result = SG_ERR_UNKNOWN;
                isComplete = true;
            }
        }
    }


    if (!isComplete)
    {
        out_buf = static_cast<uint8_t *>(malloc(sizeof(uint8_t) * (plaintext_len + EVP_CIPHER_block_size(evp_cipher))));
        if (!out_buf)
        {
            fprintf(stderr, "cannot allocate output buffer\n");
            result = SG_ERR_NOMEM;
            isComplete = true;
        }

    }

    int out_len = 0;
    if (!isComplete)
    {

        result = EVP_EncryptUpdate(ctx, out_buf, &out_len, plaintext, plaintext_len);
        if (!result)
        {
            fprintf(stderr, "cannot encrypt plaintext\n");
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }
    }

    int final_len = 0;
    if (!isComplete)
    {

        result = EVP_EncryptFinal_ex(ctx, out_buf + out_len, &final_len);
        if (!result)
        {
            fprintf(stderr, "cannot finish encrypting plaintext\n");
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }
    }

    if (!isComplete)
    {
        *output = signal_buffer_create(out_buf, out_len + final_len);
    }

    if (ctx)
    {
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
        EVP_CIPHER_CTX_free(ctx);
#else
        EVP_CIPHER_CTX_cleanup(ctx);
        free(ctx);
#endif
    }
    if (out_buf)
    {
        free(out_buf);
    }
    return result;
}

int Common::common_decrypt(signal_buffer **output,
                           int cipher,
                           const uint8_t *key, size_t key_len,
                           const uint8_t *iv, size_t iv_len,
                           const uint8_t *ciphertext, size_t ciphertext_len,
                           void *user_data)
{
    int result = 0;
    EVP_CIPHER_CTX *ctx = 0;
    uint8_t *out_buf = 0;
    bool isComplete = false;
    const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len);
    if (!evp_cipher)
    {
        fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len);
        return SG_ERR_INVAL;
    }

    if (iv_len != 16)
    {
        fprintf(stderr, "invalid AES IV size: %zu\n", iv_len);
        return SG_ERR_INVAL;
    }

    if (ciphertext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher))
    {
        fprintf(stderr, "invalid ciphertext length: %zu\n", ciphertext_len);
        return SG_ERR_UNKNOWN;
    }
    if (!isComplete)
    {
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
        ctx = EVP_CIPHER_CTX_new();
        if (!ctx)
        {
            result = SG_ERR_NOMEM;
            isComplete = true;
        }
#else
        ctx = malloc(sizeof(EVP_CIPHER_CTX));
        if(!ctx) {
            result = SG_ERR_NOMEM;
           isComplete=true;
        }
        EVP_CIPHER_CTX_init(ctx);
#endif
    }

    if (!isComplete)
    {
        result = EVP_DecryptInit_ex(ctx, evp_cipher, 0, key, iv);
        if (!result)
        {
            fprintf(stderr, "cannot initialize cipher\n");
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }
    }

    if (!isComplete)
    {
        if (cipher == SG_CIPHER_AES_CTR_NOPADDING)
        {
            result = EVP_CIPHER_CTX_set_padding(ctx, 0);
            if (!result)
            {
                fprintf(stderr, "cannot set padding\n");
                result = SG_ERR_UNKNOWN;
                isComplete = true;
            }
        }
    }

    if (!isComplete)
    {
        out_buf = static_cast<uint8_t *>(malloc(
                sizeof(uint8_t) * (ciphertext_len + EVP_CIPHER_block_size(evp_cipher))));
        if (!out_buf)
        {
            fprintf(stderr, "cannot allocate output buffer\n");
            result = SG_ERR_UNKNOWN;

            isComplete = true;
        }

    }
    int out_len = 0;
    if (!isComplete)
    {
        result = EVP_DecryptUpdate(ctx,
                                   out_buf, &out_len, ciphertext, ciphertext_len);
        if (!result)
        {
            fprintf(stderr, "cannot decrypt ciphertext\n");
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }
    }


    int final_len = 0;
    if (!isComplete)
    {
        result = EVP_DecryptFinal_ex(ctx, out_buf + out_len, &final_len);
        if (!result)
        {
            fprintf(stderr, "cannot finish decrypting ciphertext\n");
            result = SG_ERR_UNKNOWN;
            isComplete = true;
        }

    }
    if (!isComplete)
    {
        *output = signal_buffer_create(out_buf, out_len + final_len);
    }

    if (ctx)
    {
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
        EVP_CIPHER_CTX_free(ctx);
#else
        EVP_CIPHER_CTX_cleanup(ctx);
        free(ctx);
#endif
    }
    if (out_buf)
    {
        free(out_buf);
    }
    return result;
}

void Common::common_setup_crypto_provider(signal_context *context, void *user_data)
{
    signal_crypto_provider provider = {
            .random_func = common_random_generator,
            .hmac_sha256_init_func = common_hmac_sha256_init,
            .hmac_sha256_update_func = common_hmac_sha256_update,
            .hmac_sha256_final_func = common_hmac_sha256_final,
            .hmac_sha256_cleanup_func = common_hmac_sha256_cleanup,
            .sha512_digest_init_func = common_sha512_digest_init,
            .sha512_digest_update_func = common_sha512_digest_update,
            .sha512_digest_final_func = common_sha512_digest_final,
            .sha512_digest_cleanup_func = common_sha512_digest_cleanup,
            .encrypt_func = common_encrypt,
            .decrypt_func = common_decrypt,
            .user_data = user_data
    };

    signal_context_set_crypto_provider(context, &provider);
}

int Common::common_signal_context_create(signal_context **context, void *user_data)
{
    return signal_context_create(context, user_data);
}



//------------------------------------session

typedef struct {
    int64_t recipient_id;
    int32_t device_id;
} common_session_store_session_key_t;

typedef struct {
    common_session_store_session_key_t key;
    signal_buffer *record;
    UT_hash_handle hh;
} common_session_store_session_t;

typedef struct {
    common_session_store_session_t *sessions;
} common_session_store_data;

int Common::common_session_store_load_session(signal_buffer **record, signal_buffer **user_record,
                                              const signal_protocol_address *address, void *user_data)
{
    common_session_store_data *data = (common_session_store_data *) user_data;

    common_session_store_session_t *s;

    common_session_store_session_t l;
    memset(&l, 0, sizeof(common_session_store_session_t));
    l.key.recipient_id = jenkins_hash(address->name, address->name_len);
    l.key.device_id = address->device_id;
    HASH_FIND(hh, data->sessions, &l.key, sizeof(common_session_store_session_key_t), s);

    if (!s)
    {
        return 0;
    }
    signal_buffer *result = signal_buffer_copy(s->record);
    if (!result)
    {
        return SG_ERR_NOMEM;
    }
    *record = result;
    return 1;
}

int Common::common_session_store_get_sub_device_sessions(signal_int_list **sessions, const char *name,
                                                         size_t name_len, void *user_data)
{
    common_session_store_data *data = (common_session_store_data *) user_data;

    signal_int_list *result = signal_int_list_alloc();
    if (!result)
    {
        return SG_ERR_NOMEM;
    }

    int64_t recipient_hash = jenkins_hash(name, name_len);
    common_session_store_session_t *cur_node;
    common_session_store_session_t *tmp_node;
    HASH_ITER(hh, data->sessions, cur_node, tmp_node)
    {
        if (cur_node->key.recipient_id == recipient_hash)
        {
            signal_int_list_push_back(result, cur_node->key.device_id);
        }
    }

    *sessions = result;
    return 0;
}

int Common::common_session_store_store_session(const signal_protocol_address *address, uint8_t *record,
                                               size_t record_len, uint8_t *user_record_data,
                                               size_t user_record_len, void *user_data)
{
    common_session_store_data *data = (common_session_store_data *) user_data;

    common_session_store_session_t *s;

    common_session_store_session_t l;
    memset(&l, 0, sizeof(common_session_store_session_t));
    l.key.recipient_id = jenkins_hash(address->name, address->name_len);
    l.key.device_id = address->device_id;

    signal_buffer *record_buf = signal_buffer_create(record, record_len);
    if (!record_buf)
    {
        return SG_ERR_NOMEM;
    }

    HASH_FIND(hh, data->sessions, &l.key, sizeof(common_session_store_session_key_t), s);

    if (s)
    {
        signal_buffer_free(s->record);
        s->record = record_buf;
    } else
    {
        s = static_cast<common_session_store_session_t *>(malloc(sizeof(common_session_store_session_t)));
        if (!s)
        {
            signal_buffer_free(record_buf);
            return SG_ERR_NOMEM;
        }
        memset(s, 0, sizeof(common_session_store_session_t));
        s->key.recipient_id = jenkins_hash(address->name, address->name_len);
        s->key.device_id = address->device_id;
        s->record = record_buf;
        HASH_ADD(hh, data->sessions, key, sizeof(common_session_store_session_key_t), s);
    }

    return 0;
}

int
Common::common_session_store_contains_session(const signal_protocol_address *address, void *user_data)
{
    common_session_store_data *data = (common_session_store_data *) user_data;
    common_session_store_session_t *s;

    common_session_store_session_t l;
    memset(&l, 0, sizeof(common_session_store_session_t));
    l.key.recipient_id = jenkins_hash(address->name, address->name_len);
    l.key.device_id = address->device_id;

    HASH_FIND(hh, data->sessions, &l.key, sizeof(common_session_store_session_key_t), s);

    return (s == 0) ? 0 : 1;
}

int
Common::common_session_store_delete_session(const signal_protocol_address *address, void *user_data)
{
    int result = 0;
    common_session_store_data *data = (common_session_store_data *) user_data;
    common_session_store_session_t *s;

    common_session_store_session_t l;
    memset(&l, 0, sizeof(common_session_store_session_t));
    l.key.recipient_id = jenkins_hash(address->name, address->name_len);
    l.key.device_id = address->device_id;

    HASH_FIND(hh, data->sessions, &l.key, sizeof(common_session_store_session_key_t), s);

    if (s)
    {
        HASH_DEL(data->sessions, s);
        signal_buffer_free(s->record);
        free(s);
        result = 1;
    }
    return result;
}

int
Common::common_session_store_delete_all_sessions(const char *name, size_t name_len, void *user_data)
{
    int result = 0;
    common_session_store_data *data = (common_session_store_data *) user_data;

    int64_t recipient_hash = jenkins_hash(name, name_len);
    common_session_store_session_t *cur_node;
    common_session_store_session_t *tmp_node;
    HASH_ITER(hh, data->sessions, cur_node, tmp_node)
    {
        if (cur_node->key.recipient_id == recipient_hash)
        {
            HASH_DEL(data->sessions, cur_node);
            signal_buffer_free(cur_node->record);
            free(cur_node);
            result++;
        }
    }

    return result;
}

void Common::common_session_store_destroy(void *user_data)
{
    common_session_store_data *data = (common_session_store_data *) user_data;

    common_session_store_session_t *cur_node;
    common_session_store_session_t *tmp_node;
    HASH_ITER(hh, data->sessions, cur_node, tmp_node)
    {
        HASH_DEL(data->sessions, cur_node);
        signal_buffer_free(cur_node->record);
        free(cur_node);
    }

    free(data);
}

void Common::setup_common_session_store(signal_protocol_store_context *context)
{
    common_session_store_data *data = (common_session_store_data *) malloc(sizeof(common_session_store_data));
    memset(data, 0, sizeof(common_session_store_data));

    signal_protocol_session_store store = {
            .load_session_func = common_session_store_load_session,
            .get_sub_device_sessions_func = common_session_store_get_sub_device_sessions,
            .store_session_func = common_session_store_store_session,
            .contains_session_func = common_session_store_contains_session,
            .delete_session_func = common_session_store_delete_session,
            .delete_all_sessions_func = common_session_store_delete_all_sessions,
            .destroy_func = common_session_store_destroy,
            .user_data = data
    };

    signal_protocol_store_context_set_session_store(context, &store);
}

void Common::setup_common_store_context(signal_protocol_store_context **context,
                                        signal_context *global_context)
{
    int result = 0;

    signal_protocol_store_context *store_context = 0;
    result = signal_protocol_store_context_create(&store_context, global_context);
    if (result != 0)
    {
        throw CommonException(result, "setup_common_store_context error");
    }
    setup_common_session_store(store_context);
    setup_common_pre_key_store(store_context);
    setup_common_signed_pre_key_store(store_context);
//    setup_common_identity_key_store(store_context, global_context);
//    setup_common_sender_key_store(store_context, global_context);

    *context = store_context;
}


/*------------------------------------------------------------------------*/

typedef struct {
    uint32_t key_id;
    signal_buffer *key_record;
    UT_hash_handle hh;
} common_pre_key_store_key_t;

typedef struct {
    common_pre_key_store_key_t *keys;
} common_pre_key_store_data_t;

int
Common::common_pre_key_store_load_pre_key(signal_buffer **record, uint32_t pre_key_id, void *user_data)
{
    common_pre_key_store_data_t *data = (common_pre_key_store_data_t *) user_data;

    common_pre_key_store_key_t *s;

    HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s);
    if (s)
    {
        *record = signal_buffer_copy(s->key_record);
        return SG_SUCCESS;
    } else
    {
        return SG_ERR_INVALID_KEY_ID;
    }
}

int Common::common_pre_key_store_store_pre_key(uint32_t pre_key_id, uint8_t *record, size_t record_len,
                                               void *user_data)
{
    common_pre_key_store_data_t *data = (common_pre_key_store_data_t *) user_data;

    common_pre_key_store_key_t *s;

    signal_buffer *key_buf = signal_buffer_create(record, record_len);
    if (!key_buf)
    {
        return SG_ERR_NOMEM;
    }

    HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s);
    if (s)
    {
        signal_buffer_free(s->key_record);
        s->key_record = key_buf;
    } else
    {
        s = static_cast<common_pre_key_store_key_t *>(malloc(sizeof(common_pre_key_store_key_t)));
        if (!s)
        {
            signal_buffer_free(key_buf);
            return SG_ERR_NOMEM;
        }
        memset(s, 0, sizeof(common_pre_key_store_key_t));
        s->key_id = pre_key_id;
        s->key_record = key_buf;
        HASH_ADD(hh, data->keys, key_id, sizeof(uint32_t), s);
    }

    return 0;
}

int Common::common_pre_key_store_contains_pre_key(uint32_t pre_key_id, void *user_data)
{
    common_pre_key_store_data_t *data = (common_pre_key_store_data_t *) user_data;

    common_pre_key_store_key_t *s;
    HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s);

    return (s == 0) ? 0 : 1;
}

int Common::common_pre_key_store_remove_pre_key(uint32_t pre_key_id, void *user_data)
{
    common_pre_key_store_data_t *data = (common_pre_key_store_data_t *) user_data;

    common_pre_key_store_key_t *s;
    HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s);
    if (s)
    {
        HASH_DEL(data->keys, s);
        signal_buffer_free(s->key_record);
        free(s);
    }

    return 0;
}

void Common::common_pre_key_store_destroy(void *user_data)
{
    common_pre_key_store_data_t *data = (common_pre_key_store_data_t *) user_data;

    common_pre_key_store_key_t *cur_node;
    common_pre_key_store_key_t *tmp_node;
    HASH_ITER(hh, data->keys, cur_node, tmp_node)
    {
        HASH_DEL(data->keys, cur_node);
        signal_buffer_free(cur_node->key_record);
        free(cur_node);
    }
    free(data);
}

void Common::setup_common_pre_key_store(signal_protocol_store_context *context)
{
    common_pre_key_store_data_t *data = (common_pre_key_store_data_t *) malloc(sizeof(common_pre_key_store_data_t));
    memset(data, 0, sizeof(common_pre_key_store_data_t));
    signal_protocol_pre_key_store store = {
            .load_pre_key = common_pre_key_store_load_pre_key,
            .store_pre_key = common_pre_key_store_store_pre_key,
            .contains_pre_key = common_pre_key_store_contains_pre_key,
            .remove_pre_key = common_pre_key_store_remove_pre_key,
            .destroy_func = common_pre_key_store_destroy,
            .user_data = data
    };

    signal_protocol_store_context_set_pre_key_store(context, &store);
}


/*------------------------------------------------------------------------*/

typedef struct {
    uint32_t key_id;
    signal_buffer *key_record;
    UT_hash_handle hh;
} common_signed_pre_key_store_key_t;

typedef struct {
    common_signed_pre_key_store_key_t *keys;
} common_signed_pre_key_store_data_t;


int Common::common_signed_pre_key_store_load_signed_pre_key(signal_buffer **record,
                                                            uint32_t signed_pre_key_id,
                                                            void *user_data)
{
    common_signed_pre_key_store_data_t *data = (common_signed_pre_key_store_data_t *) user_data;
    common_signed_pre_key_store_key_t *s;

    HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s);
    if (s)
    {
        *record = signal_buffer_copy(s->key_record);
        return SG_SUCCESS;
    } else
    {
        return SG_ERR_INVALID_KEY_ID;
    }
}

int Common::common_signed_pre_key_store_store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record,
                                                             size_t record_len, void *user_data)
{
    common_signed_pre_key_store_data_t *data = (common_signed_pre_key_store_data_t *) user_data;
    common_signed_pre_key_store_key_t *s;

    signal_buffer *key_buf = signal_buffer_create(record, record_len);
    if (!key_buf)
    {
        return SG_ERR_NOMEM;
    }

    HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s);
    if (s)
    {
        signal_buffer_free(s->key_record);
        s->key_record = key_buf;
    } else
    {
        s = static_cast<common_signed_pre_key_store_key_t *>(malloc(sizeof(common_signed_pre_key_store_key_t)));
        if (!s)
        {
            signal_buffer_free(key_buf);
            return SG_ERR_NOMEM;
        }
        memset(s, 0, sizeof(common_signed_pre_key_store_key_t));
        s->key_id = signed_pre_key_id;
        s->key_record = key_buf;
        HASH_ADD(hh, data->keys, key_id, sizeof(uint32_t), s);
    }

    return 0;
}

int Common::common_signed_pre_key_store_contains_signed_pre_key(uint32_t signed_pre_key_id,
                                                                void *user_data)
{
    common_signed_pre_key_store_data_t *data = (common_signed_pre_key_store_data_t *) user_data;

    common_signed_pre_key_store_key_t *s;
    HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s);

    return (s == 0) ? 0 : 1;
}

int
Common::common_signed_pre_key_store_remove_signed_pre_key(uint32_t signed_pre_key_id, void *user_data)
{
    common_signed_pre_key_store_data_t *data = (common_signed_pre_key_store_data_t *) user_data;

    common_signed_pre_key_store_key_t *s;
    HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s);
    if (s)
    {
        HASH_DEL(data->keys, s);
        signal_buffer_free(s->key_record);
        free(s);
    }

    return 0;
}

void Common::common_signed_pre_key_store_destroy(void *user_data)
{
    common_signed_pre_key_store_data_t *data = (common_signed_pre_key_store_data_t *) user_data;

    common_signed_pre_key_store_key_t *cur_node;
    common_signed_pre_key_store_key_t *tmp_node;
    HASH_ITER(hh, data->keys, cur_node, tmp_node)
    {
        HASH_DEL(data->keys, cur_node);
        signal_buffer_free(cur_node->key_record);
        free(cur_node);
    }
    free(data);
}

void Common::setup_common_signed_pre_key_store(signal_protocol_store_context *context)
{
    common_signed_pre_key_store_data_t *data = (common_signed_pre_key_store_data_t *) malloc(
            sizeof(common_signed_pre_key_store_data_t));
    memset(data, 0, sizeof(common_signed_pre_key_store_data_t));

    signal_protocol_signed_pre_key_store store = {
            .load_signed_pre_key = common_signed_pre_key_store_load_signed_pre_key,
            .store_signed_pre_key = common_signed_pre_key_store_store_signed_pre_key,
            .contains_signed_pre_key = common_signed_pre_key_store_contains_signed_pre_key,
            .remove_signed_pre_key = common_signed_pre_key_store_remove_signed_pre_key,
            .destroy_func = common_signed_pre_key_store_destroy,
            .user_data = data
    };

    signal_protocol_store_context_set_signed_pre_key_store(context, &store);
}

/*------------------------------------------------------------------------*/

typedef struct {
    int64_t recipient_id;
    signal_buffer *identity_key;
    UT_hash_handle hh;
} common_identity_store_key;

typedef struct {
    common_identity_store_key *keys;
    signal_buffer *identity_key_public;
    signal_buffer *identity_key_private;
    uint32_t local_registration_id;
} common_identity_store_data;

int Common::common_identity_key_store_get_identity_key_pair(signal_buffer **public_data,
                                                            signal_buffer **private_data,
                                                            void *user_data)
{
    common_identity_store_data *data = (common_identity_store_data *) user_data;
    *public_data = signal_buffer_copy(data->identity_key_public);
    *private_data = signal_buffer_copy(data->identity_key_private);
    return 0;
}

int
Common::common_identity_key_store_get_local_registration_id(void *user_data, uint32_t *registration_id)
{
    common_identity_store_data *data = (common_identity_store_data *) user_data;
    *registration_id = data->local_registration_id;
    return 0;
}

int Common::common_identity_key_store_save_identity(const signal_protocol_address *address,
                                                    uint8_t *key_data, size_t key_len, void *user_data)
{
    common_identity_store_data *data = (common_identity_store_data *) user_data;

    common_identity_store_key *s;

    signal_buffer *key_buf = signal_buffer_create(key_data, key_len);
    if (!key_buf)
    {
        return SG_ERR_NOMEM;
    }

    int64_t recipient_hash = jenkins_hash(address->name, address->name_len);

    HASH_FIND(hh, data->keys, &recipient_hash, sizeof(int64_t), s);
    if (s)
    {
        signal_buffer_free(s->identity_key);
        s->identity_key = key_buf;
    } else
    {
        s = static_cast<common_identity_store_key *>(malloc(sizeof(common_identity_store_key)));
        if (!s)
        {
            signal_buffer_free(key_buf);
            return SG_ERR_NOMEM;
        }
        memset(s, 0, sizeof(common_identity_store_key));
        s->recipient_id = recipient_hash;
        s->identity_key = key_buf;
        HASH_ADD(hh, data->keys, recipient_id, sizeof(int64_t), s);
    }

    return 0;
}

int Common::common_identity_key_store_is_trusted_identity(const signal_protocol_address *address,
                                                          uint8_t *key_data, size_t key_len,
                                                          void *user_data)
{
    common_identity_store_data *data = (common_identity_store_data *) user_data;

    int64_t recipient_hash = jenkins_hash(address->name, address->name_len);

    common_identity_store_key *s;
    HASH_FIND(hh, data->keys, &recipient_hash, sizeof(int64_t), s);

    if (s)
    {
        uint8_t *store_data = signal_buffer_data(s->identity_key);
        size_t store_len = signal_buffer_len(s->identity_key);
        if (store_len != key_len)
        {
            return 0;
        }
        if (memcmp(key_data, store_data, key_len) == 0)
        {
            return 1;
        } else
        {
            return 0;
        }
    } else
    {
        return 1;
    }
}

void Common::common_identity_key_store_destroy(void *user_data)
{
    common_identity_store_data *data = (common_identity_store_data *) user_data;

    common_identity_store_key *cur_node;
    common_identity_store_key *tmp_node;
    HASH_ITER(hh, data->keys, cur_node, tmp_node)
    {
        HASH_DEL(data->keys, cur_node);
        signal_buffer_free(cur_node->identity_key);
        free(cur_node);
    }
    signal_buffer_free(data->identity_key_public);
    signal_buffer_free(data->identity_key_private);
    free(data);
}

void Common::setup_common_identity_key_store(signal_protocol_store_context *context,
                                             signal_context *global_context , ec_key_pair *idk , int32_t localid )
{
    common_identity_store_data *data = (common_identity_store_data *) malloc(sizeof(common_identity_store_data));
    memset(data, 0, sizeof(common_identity_store_data));

    ec_public_key *identity_key_public = ec_key_pair_get_public(idk);
    ec_private_key *identity_key_private = ec_key_pair_get_private(idk);

    ec_public_key_serialize(&data->identity_key_public, identity_key_public);
    ec_private_key_serialize(&data->identity_key_private, identity_key_private);

    data->local_registration_id = (rand() % 16380) + 1;

    signal_protocol_identity_key_store store = {
            .get_identity_key_pair = common_identity_key_store_get_identity_key_pair,
            .get_local_registration_id = common_identity_key_store_get_local_registration_id,
            .save_identity = common_identity_key_store_save_identity,
            .is_trusted_identity = common_identity_key_store_is_trusted_identity,
            .destroy_func = common_identity_key_store_destroy,
            .user_data = data
    };

    signal_protocol_store_context_set_identity_key_store(context, &store);
}


/*------------------------------------------------------------------------*/

typedef struct {
    int64_t group_id;
    int64_t recipient_id;
    int32_t device_id;
} common_sender_key_store_key_t;

typedef struct {
    common_sender_key_store_key_t key;
    signal_buffer *record;
    UT_hash_handle hh;
} common_sender_key_store_record_t;

typedef struct {
    common_sender_key_store_record_t *records;
} common_sender_key_store_data_t;

int
Common::common_sender_key_store_store_sender_key(const signal_protocol_sender_key_name *sender_key_name,
                                                 uint8_t *record, size_t record_len,
                                                 uint8_t *user_record_data, size_t user_record_len,
                                                 void *user_data)
{
    common_sender_key_store_data_t *data = (common_sender_key_store_data_t *) user_data;

    common_sender_key_store_record_t *s;

    common_sender_key_store_record_t l;
    memset(&l, 0, sizeof(common_sender_key_store_record_t));
    l.key.group_id = jenkins_hash(sender_key_name->group_id, sender_key_name->group_id_len);
    l.key.recipient_id = jenkins_hash(sender_key_name->sender.name, sender_key_name->sender.name_len);
    l.key.device_id = sender_key_name->sender.device_id;

    signal_buffer *record_buf = signal_buffer_create(record, record_len);
    if (!record_buf)
    {
        return SG_ERR_NOMEM;
    }

    HASH_FIND(hh, data->records, &l.key, sizeof(common_sender_key_store_key_t), s);

    if (s)
    {
        signal_buffer_free(s->record);
        s->record = record_buf;
    } else
    {
        s = static_cast<common_sender_key_store_record_t *>(malloc(sizeof(common_sender_key_store_record_t)));
        if (!s)
        {
            signal_buffer_free(record_buf);
            return SG_ERR_NOMEM;
        }
        memset(s, 0, sizeof(common_sender_key_store_record_t));
        s->key.group_id = jenkins_hash(sender_key_name->group_id, sender_key_name->group_id_len);
        s->key.recipient_id = jenkins_hash(sender_key_name->sender.name, sender_key_name->sender.name_len);
        s->key.device_id = sender_key_name->sender.device_id;
        s->record = record_buf;
        HASH_ADD(hh, data->records, key, sizeof(common_sender_key_store_key_t), s);
    }

    return 0;
}

int Common::common_sender_key_store_load_sender_key(signal_buffer **record, signal_buffer **user_record,
                                                    const signal_protocol_sender_key_name *sender_key_name,
                                                    void *user_data)
{
    common_sender_key_store_data_t *data = (common_sender_key_store_data_t *) user_data;

    common_sender_key_store_record_t *s;

    common_sender_key_store_record_t l;
    memset(&l, 0, sizeof(common_sender_key_store_record_t));
    l.key.group_id = jenkins_hash(sender_key_name->group_id, sender_key_name->group_id_len);
    l.key.recipient_id = jenkins_hash(sender_key_name->sender.name, sender_key_name->sender.name_len);
    l.key.device_id = sender_key_name->sender.device_id;
    HASH_FIND(hh, data->records, &l.key, sizeof(common_sender_key_store_key_t), s);

    if (!s)
    {
        return 0;
    }
    signal_buffer *result = signal_buffer_copy(s->record);
    if (!result)
    {
        return SG_ERR_NOMEM;
    }
    *record = result;
    return 1;
}

void Common::common_sender_key_store_destroy(void *user_data)
{
    common_sender_key_store_data_t *data = (common_sender_key_store_data_t *) user_data;

    common_sender_key_store_record_t *cur_node;
    common_sender_key_store_record_t *tmp_node;
    HASH_ITER(hh, data->records, cur_node, tmp_node)
    {
        HASH_DEL(data->records, cur_node);
        signal_buffer_free(cur_node->record);
        free(cur_node);
    }
    free(data);
}

void Common::setup_common_sender_key_store(signal_protocol_store_context *context,
                                           signal_context *global_context)
{
    common_sender_key_store_data_t *data = (common_sender_key_store_data_t *) malloc(
            sizeof(common_sender_key_store_data_t));
    memset(data, 0, sizeof(common_sender_key_store_data_t));

    signal_protocol_sender_key_store store = {
            .store_sender_key = common_sender_key_store_store_sender_key,
            .load_sender_key = common_sender_key_store_load_sender_key,
            .destroy_func = common_sender_key_store_destroy,
            .user_data = data
    };

    signal_protocol_store_context_set_sender_key_store(context, &store);
}


int Common::serialEcKeyPair(ec_key_pair *keyPair, KeyPairDataType &pairData)
{
    // 指针传递 不需要i释放 由外部释放
    ec_public_key *tempPub_key = ec_key_pair_get_public(keyPair);
    ec_private_key *tempPri_key = ec_key_pair_get_private(keyPair);

    // 序列化 需要释放内存
    signal_buffer *bufferPub = 0;
    int retPub = ec_public_key_serialize(&bufferPub, tempPub_key);

    if (retPub == 0)
    {
        // 成功
        pairData.publicKey = std::string((char *) bufferPub->data, bufferPub->len);
    } else
    {
        //失败
        fprintf(stderr, "get pub error ");
    }

    signal_buffer *bufferPri;
    int retPri = ec_private_key_serialize(&bufferPri, tempPri_key);

    if (retPri == 0)
    {
        // 成功
        // 构造成 字符串 对象 作为 key
        pairData.privateKey = std::string((char *) bufferPri->data, bufferPri->len);
    } else
    {
        //失败
        fprintf(stderr, "get pri error ");
    }

    // 释放 内存
    if (bufferPri) signal_buffer_free(bufferPri);
    if (bufferPub) signal_buffer_free(bufferPub);

//     全部成功才成功
    if (retPri == 0 && retPub == 0)
    {
        return EXIT_SUCCESS;
    } else
    {
        return EXIT_FAILURE;
    }
}

int Common::deserializationEcKeyPair(KeyPairDataType &pairData, ec_key_pair **keyPair, signal_context *global_context)
{
    // 反序列化

    // 存储 完成时的对象
//    ec_key_pair *tempkeyPair = 0;
    // 创建公私钥对象
    ec_public_key *tempPub_key = 0;
    ec_private_key *tempPri_key = 0;


//    uint8_t pubBuf[32];
//    uint8_t priBuf[32];
//
//    for (int i = 0; i < 32; ++i)
//    {
//        pubBuf[i] = pairData.pubKey.at(i);
//    }
//
//    for (int i = 0; i < 32; ++i)
//    {
//        priBuf[i] = pairData.priKey.at(i);
//    }

    // 公
    int retPub = curve_decode_point(&tempPub_key, (uint8_t *) pairData.publicKey.c_str(), pairData.publicKey.length(),
                                    global_context);
    // 私
    int retPrb = curve_decode_private_point(&tempPri_key, (uint8_t *) pairData.privateKey.c_str(),
                                            pairData.privateKey.length(),
                                            global_context);

    int ret = -1;
    if (retPrb == 0 && retPub == 0)
    {
        // 都成功
        ret = ec_key_pair_create(keyPair, tempPub_key, tempPri_key);
    } else
    {
        ret = -1;
    }

    // 释放内存

    if (tempPub_key)SIGNAL_UNREF(tempPub_key);
    if (tempPri_key)SIGNAL_UNREF(tempPri_key);

//    *keyPair =tempkeyPair;
//    if(tempPri_key)ec_private_key_destroy((signal_type_base *)tempPri_key);
//    if(tempPub_key)ec_public_key_destroy((signal_type_base *)tempPub_key);

    if (ret == 0)
    {
        // 成功 则传递到上层
        return EXIT_SUCCESS;
    } else
    {
        // 失败 则销毁

        return EXIT_FAILURE;
    }

}

bool Common::serialEcPubKey(ec_public_key *public_key, std::string &serialStr)
{
    // 序列化 需要释放内存
    signal_buffer *buffer = 0;
    int retPub = ec_public_key_serialize(&buffer, public_key);

    bool retStatus = false;

    if (retPub == 0)
    {
        // 成功
        serialStr.copy((char *) buffer->data, buffer->len);
        retStatus = true;

    } else
    {
        //失败
        fprintf(stderr, "get pub error ");
        retStatus = false;
    }

    if (buffer) signal_buffer_free(buffer);

    return retStatus;
}

bool Common::serialEcPriKey(ec_private_key *private_key, std::string &serialStr)
{
    // 序列化 需要释放内存
    signal_buffer *buffer = 0;
    int retPub = ec_private_key_serialize(&buffer, private_key);
    bool retStatus = false;
    if (retPub == 0)
    {
        // 成功
        serialStr.copy((char *) buffer->data, buffer->len);
        retStatus = true;

    } else
    {
        //失败
        fprintf(stderr, "get pri error ");
        retStatus = false;
    }

    if (buffer) signal_buffer_free(buffer);

    return retStatus;
}

int Common::serialRatchetKeyPair(ratchet_identity_key_pair *keyPair, KeyPairDataType &pairData)
{
    // 返回 rathet idk

    int ret = 0;

    ec_public_key *temp_pub_key = ratchet_identity_key_pair_get_public(keyPair);
    ec_private_key *temp_pri_key = ratchet_identity_key_pair_get_private(keyPair);

    bool isOk = false;

    if (temp_pub_key && temp_pri_key)
    {
        // 存在数据
        isOk = true;
    } else
    {
        // 数据不完整
        isOk = false;
    }


    //释放内存 不需要
    if (isOk)
    {
        // 存在数据 则 拼接

        std::string tempKey;

        if (serialEcPriKey(temp_pri_key, tempKey) == EXIT_SUCCESS)
        {
            // 序列化成功
            pairData.privateKey = tempKey;
        }

        if (serialEcPubKey(temp_pub_key, tempKey) == EXIT_SUCCESS)
        {
            pairData.publicKey = tempKey;
        }

        return EXIT_SUCCESS;
    } else
    {
        // 不存在数据
        return EXIT_FAILURE;
    }


}

int Common::deserializationRatchetKeyPair(KeyPairDataType &pairData, ratchet_identity_key_pair **keyPair,
                                          signal_context *global_context)
{

    // 公私钥对
    ec_public_key *temp_pub_key = 0;
    ec_private_key *temp_pri_key = 0;

    int ret = deserializationEcPriKey(pairData.privateKey, &temp_pri_key, global_context);

    if (ret == 0)
    {
        // ok
    } else
    {
        // no
    }

    ret = deserializationEcPubKey(pairData.publicKey, &temp_pub_key, global_context);

    if (ret == 0)
    {
        // ok
    } else
    {
        // no
    }

    ret = ratchet_identity_key_pair_create(keyPair, temp_pub_key, temp_pri_key);

    if (ret == 0)
    {
        // ok
        return true;
    } else
    {
        // no
        return false;
    }


}

bool Common::deserializationEcPubKey(std::string &pubKey, ec_public_key **public_key, signal_context *global_context)
{
    int retPub = curve_decode_point(public_key, (uint8_t *) pubKey.c_str(), pubKey.length(),
                                    global_context);
    if (retPub == 0)
    {
        return true;
    } else
    {
        return false;
    }
}

bool Common::deserializationEcPriKey(std::string &priKey, ec_private_key **private_key, signal_context *global_context)
{
    int retPrb = curve_decode_private_point(private_key, (uint8_t *) priKey.c_str(), priKey.length(),
                                            global_context);
    if (retPrb == 0)
    {
        return true;
    } else
    {
        return false;
    }
}

int Common::creatEcKeyPack(KeyPairDataType &pairData, signal_context *global_context)
{
    ec_key_pair *key_pair = 0;
    int result = curve_generate_key_pair(global_context, &key_pair);
    int retCode = EXIT_SUCCESS;
    if (result == 0)
    {
        // 成功
        retCode = serialEcKeyPair(key_pair, pairData);

    } else
    {
        retCode = EXIT_FAILURE;
    }
    // 释放内存
    if (key_pair)ec_key_pair_destroy((signal_type_base *) key_pair);

    return retCode;
}


const std::string HexCode = "0123456789ABCDEF";


std::string Common::StringToHex(const std::string &data)
{

    std::string result;
    uint8_t currTemp = 0;
    for (int i = 0; i < data.size(); ++i)
    {
        currTemp = data[i] & 0xff;
        result.push_back(HexCode[currTemp >> 4]);
        result.push_back(HexCode[currTemp & 0x0f]);
    }
    return result;
}

std::string Common::HexToString(const std::string &data)
{
    std::string result;
    for (int i = 0; i < data.length(); i += 2)
    {
        std::string byte = data.substr(i, 2);
        char chr = (char) strtol(byte.c_str(), NULL, 16);
        result.push_back(chr);
    }
    return result;
}